package com.zzyl.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.crypto.digest.BCrypt;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.zzyl.base.PageResponse;
import com.zzyl.constant.SuperConstant;
import com.zzyl.dto.UserDto;
import com.zzyl.entity.User;
import com.zzyl.entity.UserRole;
import com.zzyl.enums.BasicEnum;
import com.zzyl.exception.BaseException;
import com.zzyl.mapper.DeptMapper;
import com.zzyl.mapper.UserMapper;
import com.zzyl.mapper.UserRoleMapper;
import com.zzyl.properties.SecurityConfigProperties;
import com.zzyl.service.UserService;
import com.zzyl.utils.EmptyUtil;
import com.zzyl.utils.NoProcessing;
import com.zzyl.utils.UserThreadLocal;
import com.zzyl.vo.RoleVo;
import com.zzyl.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @Description UserServiceImpl
 * @Author chenchuang
 * @Date 2024-09-01
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserRoleMapper userRoleMapper;

    @Autowired
    private DeptMapper deptMapper;

    @Autowired
    private SecurityConfigProperties securityConfigProperties;
    @Override
    public PageResponse<UserVo> getByPage(UserDto userDto, Integer pageNum, Integer pageSize) {

        if (!EmptyUtil.isNullOrEmpty(userDto.getDeptNo())) {
            userDto.setDeptNo(NoProcessing.processString(userDto.getDeptNo()));
        }
        PageHelper.startPage(pageNum, pageSize);
        Page<List<User>> page = userMapper.selectPage(userDto);
        PageResponse<UserVo> pageResponse = PageResponse.of(page, UserVo.class);
        if(!EmptyUtil.isNullOrEmpty(pageResponse.getRecords())){
            List<Long> userIds = pageResponse.getRecords().stream().map(UserVo::getId).collect(Collectors.toList());
            List<RoleVo> roleVoList = userMapper.findRoleVoListInUserId(userIds);
            pageResponse.getRecords().forEach(r->{
                Set<String> roleIds = new HashSet<>();
                Set<String> roleLabels = new HashSet<>();
                roleVoList.forEach(roleVo -> {
                    if (String.valueOf(r.getId()).equals(roleVo.getUserId())) {
                        roleIds.add(String.valueOf(roleVo.getId()));
                        roleLabels.add(roleVo.getRoleName());
                    }
                });
                r.setRoleVoIds(roleIds);
                r.setRoleLabels(roleLabels);
            });
        }
        return pageResponse;
    }

    @Transactional
    @Override
    public void createUser(UserDto userDto) {

        //根据部门编号查询，是否是最底层的部门，如果不是，不允许添加用户
        if (isLowestDept(userDto.getDeptNo())) {
            throw new BaseException(BasicEnum.USER_LOCATED_BOTTOMED_DEPT);
        }
        User user = BeanUtil.copyProperties(userDto, User.class);
        user.setUsername(user.getEmail());
        user.setNickName(user.getRealName());
        user.setDataState(SuperConstant.DATA_STATE_0);
        //TODO 需要设置默认，并且需要加密
        String password = BCrypt.hashpw(securityConfigProperties.getDefaultPassword(), BCrypt.gensalt());
        user.setPassword(password);
        Set<String> roleIds = userDto.getRoleVoIds();
        userMapper.insertSelective(user);
        roleIds.forEach(roleId -> {
            UserRole build = UserRole.builder().roleId(Long.valueOf(roleId))
                    .userId(user.getId())
                    .dataState(SuperConstant.DATA_STATE_0).build();
            userRoleMapper.insertSelective(build);
        });
    }

    @Transactional
    @Override
    public void updateUser(UserDto userDto) {
        User user = BeanUtil.copyProperties(userDto, User.class);
        int flag = userMapper.updateByPrimaryKeySelective(user);
        if (flag <= 0) {
            throw new RuntimeException("修改用户信息出错");
        }

        if (!EmptyUtil.isNullOrEmpty(userDto.getRoleVoIds())) {
            //先删除用户角色关系
            userRoleMapper.deleteByUserId(user.getId());
            //重新添加用户角色关系
            Set<String> roleIds = userDto.getRoleVoIds();
            roleIds.forEach(roleId -> {
                UserRole build = UserRole.builder().roleId(Long.valueOf(roleId))
                        .userId(user.getId())
                        .dataState(SuperConstant.DATA_STATE_0).build();
                userRoleMapper.insertSelective(build);
            });
        }
    }

    @Override
    public UserVo currentUser() {
        Long userId = UserThreadLocal.getUserId();
        User user =userMapper.selectByPrimaryKey(userId);
        return BeanUtil.copyProperties(user, UserVo.class);
    }

    @Override
    public void updateUserStatus(Long id, String status) {
        User user = userMapper.selectByPrimaryKey(id);
        if (user == null) {
            throw new BaseException(BasicEnum.USER_EMPTY_EXCEPTION);
        }
        user.setDataState(status);
        userMapper.updateByPrimaryKeySelective(user);
    }

    @Transactional
    @Override
    public void deleteById(Long userId) {
        userRoleMapper.deleteByUserId(userId);
        userMapper.deleteByPrimaryKey(userId);
    }

    @Override
    public void resetPasswords(Long userId) {
        String password = BCrypt.hashpw(securityConfigProperties.getDefaultPassword(), BCrypt.gensalt());
        User build = User.builder().password(password).build();
        build.setId(userId);
        userMapper.updateByPrimaryKeySelective(build);
    }

    @Override
    public List<UserVo> selectList(UserDto userDto) {
        List<User> users =userMapper.selectAll();
        List<UserVo> userVos = BeanUtil.copyToList(users, UserVo.class);
        return userVos;
    }

    /**
     * 判断是否是最底层部门
     *
     * @return
     */
    private boolean isLowestDept(String deptNo) {
        int count = deptMapper.isLowestDept(deptNo);
        if (count > 0) {
            return true;
        }
        return false;
    }
}
